#pragma once

#include <QVector>
#include <QString>
#include <QHash>
#include <QApplication>
#include <QCommandLineOption>
#include <QCommandLineParser>
#include <QMutex>
#include <QMutexLocker>
#include "except.hpp"
#include "log.hpp"

namespace cloud
{

struct optionHelper
{
public:
    optionHelper(const QString& name = "") : _opt(name) {}
    QCommandLineOption _opt;
};

class CmdHelper
{
public:
    static CmdHelper* instance()
    {
        if (_inst == nullptr)
            THROW("use cmdHelper instance must initialize it first");
        return _inst;
    }

    static CmdHelper* instance(const QApplication& app, const QHash<QString, QString>& kvs)
    {
        if (_inst == nullptr)
        {
            QMutexLocker lock(&_mtx); // RAII automatic locker

            if (_inst == nullptr)
                _inst = new CmdHelper(app, kvs);
        }
        return _inst;
    }

    QString value(const QString& key)
    {
        return _parser->value((*_key2opt)[key]._opt);
    }

private:
    CmdHelper(const QApplication& app, const QHash<QString, QString>& kvs)
        : _key2opt(new QHash<QString, optionHelper>)
        , _parser(new QCommandLineParser)
    {
        _parser->setApplicationDescription("Cloud client embedded");
        _parser->addHelpOption();
        _parser->addVersionOption();

        auto& key2opt = *_key2opt;

        foreach (const QString &key, kvs.keys())
        {
            key2opt.insert(key, optionHelper(key));
            key2opt[key]._opt.setValueName(kvs.value(key)); // Add comments to options, view them in help
            _parser->addOption(key2opt[key]._opt); // Add option in parser
        }

        INFO("cmdline parms parser's instance initialized success");
        _parser->process(app);
    }

    CmdHelper(CmdHelper const&) = delete;
    void operator=(CmdHelper const&) = delete;

private:
    QHash<QString, optionHelper>* _key2opt;
    QCommandLineParser* _parser;

    static CmdHelper* _inst;
    static QMutex _mtx;
};

}
